using System;
using System.Collections.Generic;
using System.IO;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Measurement;
using ZoneFiveSoftware.Common.Data.Fitness;
using FilteredStatistics.View;

namespace FilteredStatistics.Data
{
    class MergeNearTimesPostProcessFilter : IPostProcessFilter
    {
        public MergeNearTimesPostProcessFilter(Stream stream, DataVersion version)
        {
            Deserialize(stream, version);
        }

        public MergeNearTimesPostProcessFilter(TimeSpan maxGapTime)
        {
            m_MaxGapTime = maxGapTime;
        }

#region IPostProcessFilter Members

        public override PostProcessType Type
        {
            get { return PostProcessType.MergeNearTimes; }
        }

        public override String DisplayString
        {
            get
            {
                return String.Format(PluginView.GetLocalizedString("MergeNearTimesPPText"),
                                     m_MaxGapTime.Hours, m_MaxGapTime.Minutes, m_MaxGapTime.Seconds);
            }
        }

        public override List<ActivityRangeInfoCache> FilterResults(IList<ActivityRangeInfoCache> rangesToFilter, IActivity activity)
        {
            List<ActivityRangeInfoCache> result = new List<ActivityRangeInfoCache>();
            bool mergedLast = false;

            for (int i = 0; i < rangesToFilter.Count - 1; ++i)
            {
                ActivityRangeInfoCache currentRange = rangesToFilter[i];
                ActivityRangeInfoCache nextRange = rangesToFilter[i + 1];
                TimeSpan timeGap = nextRange.PauselessRange.Lower - currentRange.PauselessRange.Upper;

                if (timeGap > m_MaxGapTime)
                {
                    // Make sure not to add twice when re-evaluating
                    if (!mergedLast)
                    {
                        result.Add(currentRange);
                    }

                    mergedLast = false;
                }
                else
                {
                    ActivityRangeInfoCache merged = new ActivityRangeInfoCache(new ValueRange<DateTime>(currentRange.RangeWithPauses.Lower,
                                                                                                        nextRange.RangeWithPauses.Upper),
                                                                                                        activity);

                    if (mergedLast)
                    {
                        // Overwrite, if many successive merges
                        result[result.Count - 1] = merged;
                    }
                    else
                    {
                        result.Add(merged);
                    }

                    // Setup for next attempt
                    rangesToFilter[i] = merged;
                    rangesToFilter.RemoveAt(i + 1);
                    mergedLast = true;
                    --i;
                }
            }
            
            // Add the last if required
            if (!mergedLast && rangesToFilter.Count > 0)
            {
                result.Add(rangesToFilter[rangesToFilter.Count - 1]);
            }

            return result;
        }

        public override int CompareTo(IPostProcessFilter filter)
        {
            if (filter is MergeNearDistancesPostProcessFilter ||
                filter is MergeNearTimesPostProcessFilter)
            {
                return 0;
            }

            return -1;
        }

#endregion

#region IPluginSerializable members

        public override void Serialize(Stream stream)
        {
            base.Serialize(stream);

            SerializableTimeSpan maxGap = new SerializableTimeSpan(m_MaxGapTime);

            maxGap.Serialize(stream);
        }

#endregion

#region Deserialization methods

        public override void Deserialize_V2(Stream stream, DataVersion version)
        {
            SerializableTimeSpan maxGap = new SerializableTimeSpan(0);

            maxGap.Deserialize(stream, version);

            m_MaxGapTime = maxGap;
        }

#endregion

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            MergeNearTimesPostProcessFilter filter = obj as MergeNearTimesPostProcessFilter;

            if (filter != null)
            {
                return MaxGapTime == filter.MaxGapTime;
            }

            return base.Equals(obj);
        }

        public TimeSpan MaxGapTime
        {
            get { return m_MaxGapTime; }
        }

        private TimeSpan m_MaxGapTime;
    }
}
